From: Raspbian kernel package updater Date: Sun, 23 Jul 2017 01:53:10 +0000 (+0000) Subject: remove some debian patches that conflict with rpi stuff X-Git-Tag: archive/raspbian/4.9.30-2+deb9u2+rpi1~7 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=62741b0279980d3feb0a9eeacfec695f5294449c;p=linux-4.9.git remove some debian patches that conflict with rpi stuff --- diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index cbe09c71fceb..be36da42fe06 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3932,13 +3932,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. spia_pedr= spia_peddr= - stack_guard_gap= [MM] - override the default stack gap protection. The value - is in page units and it defines how many pages prior - to (for stacks growing down) resp. after (for stacks - growing up) the main stack are reserved for no other - mapping. Default value is 256 pages. - stacktrace [FTRACE] Enabled the stack tracer on boot up. diff --git a/arch/arc/mm/mmap.c b/arch/arc/mm/mmap.c index cf4ae6958240..2e06d56e987b 100644 --- a/arch/arc/mm/mmap.c +++ b/arch/arc/mm/mmap.c @@ -64,7 +64,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 641334ebf46d..66353caa35b9 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -89,7 +89,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -140,7 +140,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c index efa59f1f8022..836f14707a62 100644 --- a/arch/frv/mm/elf-fdpic.c +++ b/arch/frv/mm/elf-fdpic.c @@ -74,7 +74,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi addr = PAGE_ALIGN(addr); vma = find_vma(current->mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) goto success; } diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index a44052c05f93..d08ea3ff0f53 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -92,7 +92,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 1d7691fa8ab2..0a393a04e891 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -88,7 +88,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma, *prev; + struct vm_area_struct *vma; unsigned long task_size = TASK_SIZE; int do_color_align, last_mmap; struct vm_unmapped_area_info info; @@ -115,10 +115,9 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, else addr = PAGE_ALIGN(addr); - vma = find_vma_prev(mm, addr, &prev); + vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vm_start_gap(vma)) && - (!prev || addr >= vm_end_gap(prev))) + (!vma || addr + len <= vma->vm_start)) goto found_addr; } @@ -142,7 +141,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, const unsigned long len, const unsigned long pgoff, const unsigned long flags) { - struct vm_area_struct *vma, *prev; + struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr = addr0; int do_color_align, last_mmap; @@ -176,11 +175,9 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = COLOR_ALIGN(addr, last_mmap, pgoff); else addr = PAGE_ALIGN(addr); - - vma = find_vma_prev(mm, addr, &prev); + vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma)) && - (!prev || addr >= vm_end_gap(prev))) + (!vma || addr + len <= vma->vm_start)) goto found_addr; } diff --git a/arch/powerpc/mm/hugetlbpage-radix.c b/arch/powerpc/mm/hugetlbpage-radix.c index a2b2d97f7eda..35254a678456 100644 --- a/arch/powerpc/mm/hugetlbpage-radix.c +++ b/arch/powerpc/mm/hugetlbpage-radix.c @@ -65,7 +65,7 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } /* diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c index 5bc2845cddf4..2f1e44362198 100644 --- a/arch/powerpc/mm/mmap.c +++ b/arch/powerpc/mm/mmap.c @@ -106,7 +106,7 @@ radix__arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -142,7 +142,7 @@ radix__arch_get_unmapped_area_topdown(struct file *filp, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index c4d5c9c61e0f..2b27458902ee 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -105,7 +105,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr, if ((mm->task_size - len) < addr) return 0; vma = find_vma(mm, addr); - return (!vma || (addr + len) <= vm_start_gap(vma)); + return (!vma || (addr + len) <= vma->vm_start); } static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice) diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 812368f274c9..eb9df2822da1 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -98,7 +98,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -136,7 +136,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 7df7d5944188..6777177807c2 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -63,7 +63,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -113,7 +113,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 02e05e221b94..fe8b8ee8e660 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -118,7 +118,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -181,7 +181,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 58cde8d9be8a..988acc8b1b80 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -116,7 +116,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index 67508b249ede..77ceaa343fce 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c @@ -232,7 +232,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } if (current->mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 1119414ab419..a55ed63b9f91 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -140,7 +140,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (end - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -183,7 +183,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index fe342e8ed529..2ae8584b44c7 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -144,7 +144,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c index 3aaaae18417c..83cf49685373 100644 --- a/arch/xtensa/kernel/syscall.c +++ b/arch/xtensa/kernel/syscall.c @@ -87,7 +87,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, /* At this point: (!vmm || addr < vmm->vm_end). */ if (TASK_SIZE - len < addr) return -ENOMEM; - if (!vmm || addr + len <= vm_start_gap(vmm)) + if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; if (flags & MAP_SHARED) diff --git a/debian/patches/series b/debian/patches/series index 8acf87f4fc4b..e38bde46260e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -46,7 +46,6 @@ debian/btrfs-warn-about-raid5-6-being-experimental-at-mount.patch debian/amd64-don-t-warn-about-expected-w+x-pages-on-xen.patch # Arch bug fixes bugfix/arm/arm-dts-kirkwood-fix-sata-pinmux-ing-for-ts419.patch -bugfix/x86/pinctrl-cherryview-add-a-quirk-to-make-acer-chromebo.patch # Arch features features/mips/MIPS-increase-MAX-PHYSMEM-BITS-on-Loongson-3-only.patch features/mips/MIPS-Loongson-3-Add-Loongson-LS3A-RS780E-1-way-machi.patch @@ -108,7 +107,6 @@ bugfix/all/sctp-do-not-inherit-ipv6_-mc-ac-fl-_list-from-parent.patch bugfix/all/ipv6-dccp-do-not-inherit-ipv6_mc_list-from-parent.patch bugfix/all/crypto-skcipher-Add-missing-api-setkey-checks.patch bugfix/all/ipv6-fix-out-of-bound-writes-in-__ip6_append_data.patch -bugfix/all/mm-larger-stack-guard-gap-between-vmas.patch bugfix/all/mm-fix-new-crash-in-unmapped_area_topdown.patch # Fix exported symbol versions bugfix/ia64/revert-ia64-move-exports-to-definitions.patch diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 007770facdeb..c43b1e9a06af 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -13,7 +13,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include @@ -1525,31 +1524,10 @@ static void chv_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -/* - * Certain machines seem to hardcode Linux IRQ numbers in their ACPI - * tables. Since we leave GPIOs that are not capable of generating - * interrupts out of the irqdomain the numbering will be different and - * cause devices using the hardcoded IRQ numbers fail. In order not to - * break such machines we will only mask pins from irqdomain if the machine - * is not listed below. - */ -static const struct dmi_system_id chv_no_valid_mask[] = { - { - /* See https://bugzilla.kernel.org/show_bug.cgi?id=194945 */ - .ident = "Acer Chromebook (CYAN)", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), - DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"), - DMI_MATCH(DMI_BIOS_DATE, "05/21/2016"), - }, - } -}; - static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) { const struct chv_gpio_pinrange *range; struct gpio_chip *chip = &pctrl->chip; - bool need_valid_mask = !dmi_check_system(chv_no_valid_mask); int ret, i, offset; *chip = chv_gpio_chip; @@ -1558,7 +1536,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) chip->label = dev_name(pctrl->dev); chip->parent = pctrl->dev; chip->base = -1; - chip->irq_need_valid_mask = need_valid_mask; + chip->irq_need_valid_mask = true; ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl); if (ret) { @@ -1589,7 +1567,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) intsel &= CHV_PADCTRL0_INTSEL_MASK; intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; - if (need_valid_mask && intsel >= pctrl->community->nirqs) + if (intsel >= pctrl->community->nirqs) clear_bit(i, chip->irq_valid_mask); } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 704fa0b17309..4fb7b10f3a05 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -191,7 +191,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) + (!vma || addr + len <= vma->vm_start)) return addr; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 77a4ec2a0ebd..f539b33a7930 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -302,7 +302,11 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) /* We don't show the stack guard page in /proc/maps */ start = vma->vm_start; + if (stack_guard_page_start(vma, start)) + start += PAGE_SIZE; end = vma->vm_end; + if (stack_guard_page_end(vma, end)) + end -= PAGE_SIZE; seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ", diff --git a/include/linux/mm.h b/include/linux/mm.h index bea7c55250d6..77b1438f5b3b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1378,11 +1378,39 @@ int clear_page_dirty_for_io(struct page *page); int get_cmdline(struct task_struct *task, char *buffer, int buflen); +/* Is the vma a continuation of the stack vma above it? */ +static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) +{ + return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); +} + static inline bool vma_is_anonymous(struct vm_area_struct *vma) { return !vma->vm_ops; } +static inline int stack_guard_page_start(struct vm_area_struct *vma, + unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSDOWN) && + (vma->vm_start == addr) && + !vma_growsdown(vma->vm_prev, addr); +} + +/* Is the vma a continuation of the stack vma below it? */ +static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) +{ + return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); +} + +static inline int stack_guard_page_end(struct vm_area_struct *vma, + unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSUP) && + (vma->vm_end == addr) && + !vma_growsup(vma->vm_next, addr); +} + int vma_is_stack_for_current(struct vm_area_struct *vma); extern unsigned long move_page_tables(struct vm_area_struct *vma, @@ -2121,7 +2149,6 @@ void page_cache_async_readahead(struct address_space *mapping, pgoff_t offset, unsigned long size); -extern unsigned long stack_guard_gap; /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */ extern int expand_stack(struct vm_area_struct *vma, unsigned long address); @@ -2150,30 +2177,6 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m return vma; } -static inline unsigned long vm_start_gap(struct vm_area_struct *vma) -{ - unsigned long vm_start = vma->vm_start; - - if (vma->vm_flags & VM_GROWSDOWN) { - vm_start -= stack_guard_gap; - if (vm_start > vma->vm_start) - vm_start = 0; - } - return vm_start; -} - -static inline unsigned long vm_end_gap(struct vm_area_struct *vma) -{ - unsigned long vm_end = vma->vm_end; - - if (vma->vm_flags & VM_GROWSUP) { - vm_end += stack_guard_gap; - if (vm_end < vma->vm_end) - vm_end = -PAGE_SIZE; - } - return vm_end; -} - static inline unsigned long vma_pages(struct vm_area_struct *vma) { return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; diff --git a/mm/gup.c b/mm/gup.c index c63a0341ae38..ec4f82704b6f 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -370,6 +370,11 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, /* mlock all present pages, but do not fault in new pages */ if ((*flags & (FOLL_POPULATE | FOLL_MLOCK)) == FOLL_MLOCK) return -ENOENT; + /* For mm_populate(), just skip the stack guard page. */ + if ((*flags & FOLL_POPULATE) && + (stack_guard_page_start(vma, address) || + stack_guard_page_end(vma, address + PAGE_SIZE))) + return -ENOENT; if (*flags & FOLL_WRITE) fault_flags |= FAULT_FLAG_WRITE; if (*flags & FOLL_REMOTE) diff --git a/mm/memory.c b/mm/memory.c index 25facf71e400..150737f0a1dc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2698,6 +2698,40 @@ out_release: return ret; } +/* + * This is like a special single-page "expand_{down|up}wards()", + * except we must first make sure that 'address{-|+}PAGE_SIZE' + * doesn't hit another vma. + */ +static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) +{ + address &= PAGE_MASK; + if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { + struct vm_area_struct *prev = vma->vm_prev; + + /* + * Is there a mapping abutting this one below? + * + * That's only ok if it's the same stack mapping + * that has gotten split.. + */ + if (prev && prev->vm_end == address) + return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; + + return expand_downwards(vma, address - PAGE_SIZE); + } + if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { + struct vm_area_struct *next = vma->vm_next; + + /* As VM_GROWSDOWN but s/below/above/ */ + if (next && next->vm_start == address + PAGE_SIZE) + return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; + + return expand_upwards(vma, address + PAGE_SIZE); + } + return 0; +} + /* * We enter with non-exclusive mmap_sem (to exclude vma changes, * but allow concurrent faults), and pte mapped but not yet locked. @@ -2714,6 +2748,10 @@ static int do_anonymous_page(struct fault_env *fe) if (vma->vm_flags & VM_SHARED) return VM_FAULT_SIGBUS; + /* Check if we need to add a guard page to the stack */ + if (check_stack_guard_page(vma, fe->address) < 0) + return VM_FAULT_SIGSEGV; + /* * Use pte_alloc() instead of pte_alloc_map(). We can't run * pte_offset_map() on pmds where a huge pmd might be created diff --git a/mm/mmap.c b/mm/mmap.c index ccbf085caab8..67c56294a8d4 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -183,7 +183,6 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) unsigned long retval; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; - struct vm_area_struct *next; unsigned long min_brk; bool populate; @@ -229,8 +228,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) } /* Check against existing mmap mappings. */ - next = find_vma(mm, oldbrk); - if (next && newbrk + PAGE_SIZE > vm_start_gap(next)) + if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) goto out; /* Ok, looks good - let it rip. */ @@ -253,22 +251,10 @@ out: static long vma_compute_subtree_gap(struct vm_area_struct *vma) { - unsigned long max, prev_end, subtree_gap; - - /* - * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we - * allow two stack_guard_gaps between them here, and when choosing - * an unmapped area; whereas when expanding we only require one. - * That's a little inconsistent, but keeps the code here simpler. - */ - max = vm_start_gap(vma); - if (vma->vm_prev) { - prev_end = vm_end_gap(vma->vm_prev); - if (max > prev_end) - max -= prev_end; - else - max = 0; - } + unsigned long max, subtree_gap; + max = vma->vm_start; + if (vma->vm_prev) + max -= vma->vm_prev->vm_end; if (vma->vm_rb.rb_left) { subtree_gap = rb_entry(vma->vm_rb.rb_left, struct vm_area_struct, vm_rb)->rb_subtree_gap; @@ -364,7 +350,7 @@ static void validate_mm(struct mm_struct *mm) anon_vma_unlock_read(anon_vma); } - highest_address = vm_end_gap(vma); + highest_address = vma->vm_end; vma = vma->vm_next; i++; } @@ -553,7 +539,7 @@ void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, if (vma->vm_next) vma_gap_update(vma->vm_next); else - mm->highest_vm_end = vm_end_gap(vma); + mm->highest_vm_end = vma->vm_end; /* * vma->vm_prev wasn't known when we followed the rbtree to find the @@ -868,7 +854,7 @@ again: vma_gap_update(vma); if (end_changed) { if (!next) - mm->highest_vm_end = vm_end_gap(vma); + mm->highest_vm_end = end; else if (!adjust_next) vma_gap_update(next); } @@ -953,7 +939,7 @@ again: * mm->highest_vm_end doesn't need any update * in remove_next == 1 case. */ - VM_WARN_ON(mm->highest_vm_end != vm_end_gap(vma)); + VM_WARN_ON(mm->highest_vm_end != end); } } if (insert && file) @@ -1797,7 +1783,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) while (true) { /* Visit left subtree if it looks promising */ - gap_end = vm_start_gap(vma); + gap_end = vma->vm_start; if (gap_end >= low_limit && vma->vm_rb.rb_left) { struct vm_area_struct *left = rb_entry(vma->vm_rb.rb_left, @@ -1808,7 +1794,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) } } - gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; + gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; check_current: /* Check if current node has a suitable gap */ if (gap_start > high_limit) @@ -1836,8 +1822,8 @@ check_current: vma = rb_entry(rb_parent(prev), struct vm_area_struct, vm_rb); if (prev == vma->vm_rb.rb_left) { - gap_start = vm_end_gap(vma->vm_prev); - gap_end = vm_start_gap(vma); + gap_start = vma->vm_prev->vm_end; + gap_end = vma->vm_start; goto check_current; } } @@ -1901,7 +1887,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) while (true) { /* Visit right subtree if it looks promising */ - gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; + gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; if (gap_start <= high_limit && vma->vm_rb.rb_right) { struct vm_area_struct *right = rb_entry(vma->vm_rb.rb_right, @@ -1914,7 +1900,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) check_current: /* Check if current node has a suitable gap */ - gap_end = vm_start_gap(vma); + gap_end = vma->vm_start; if (gap_end < low_limit) return -ENOMEM; if (gap_start <= high_limit && @@ -1941,7 +1927,7 @@ check_current: struct vm_area_struct, vm_rb); if (prev == vma->vm_rb.rb_right) { gap_start = vma->vm_prev ? - vm_end_gap(vma->vm_prev) : 0; + vma->vm_prev->vm_end : 0; goto check_current; } } @@ -1979,7 +1965,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma, *prev; + struct vm_area_struct *vma; struct vm_unmapped_area_info info; if (len > TASK_SIZE - mmap_min_addr) @@ -1990,10 +1976,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma_prev(mm, addr, &prev); + vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma)) && - (!prev || addr >= vm_end_gap(prev))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -2016,7 +2001,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, const unsigned long len, const unsigned long pgoff, const unsigned long flags) { - struct vm_area_struct *vma, *prev; + struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr = addr0; struct vm_unmapped_area_info info; @@ -2031,10 +2016,9 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma_prev(mm, addr, &prev); + vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma)) && - (!prev || addr >= vm_end_gap(prev))) + (!vma || addr + len <= vma->vm_start)) return addr; } @@ -2169,19 +2153,21 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr, * update accounting. This is shared with both the * grow-up and grow-down cases. */ -static int acct_stack_growth(struct vm_area_struct *vma, - unsigned long size, unsigned long grow) +static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow) { struct mm_struct *mm = vma->vm_mm; struct rlimit *rlim = current->signal->rlim; - unsigned long new_start; + unsigned long new_start, actual_size; /* address space limit tests */ if (!may_expand_vm(mm, vma->vm_flags, grow)) return -ENOMEM; /* Stack limit test */ - if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) + actual_size = size; + if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) + actual_size -= PAGE_SIZE; + if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) return -ENOMEM; /* mlock limit tests */ @@ -2219,29 +2205,16 @@ static int acct_stack_growth(struct vm_area_struct *vma, int expand_upwards(struct vm_area_struct *vma, unsigned long address) { struct mm_struct *mm = vma->vm_mm; - struct vm_area_struct *next; - unsigned long gap_addr; int error = 0; if (!(vma->vm_flags & VM_GROWSUP)) return -EFAULT; /* Guard against wrapping around to address 0. */ - address &= PAGE_MASK; - address += PAGE_SIZE; - if (!address) - return -ENOMEM; - - /* Enforce stack_guard_gap */ - gap_addr = address + stack_guard_gap; - if (gap_addr < address) + if (address < PAGE_ALIGN(address+4)) + address = PAGE_ALIGN(address+4); + else return -ENOMEM; - next = vma->vm_next; - if (next && next->vm_start < gap_addr) { - if (!(next->vm_flags & VM_GROWSUP)) - return -ENOMEM; - /* Check that both stack segments have the same anon_vma? */ - } /* We must make sure the anon_vma is allocated. */ if (unlikely(anon_vma_prepare(vma))) @@ -2286,7 +2259,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) if (vma->vm_next) vma_gap_update(vma->vm_next); else - mm->highest_vm_end = vm_end_gap(vma); + mm->highest_vm_end = address; spin_unlock(&mm->page_table_lock); perf_event_mmap(vma); @@ -2307,8 +2280,6 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address) { struct mm_struct *mm = vma->vm_mm; - struct vm_area_struct *prev; - unsigned long gap_addr; int error; address &= PAGE_MASK; @@ -2316,17 +2287,6 @@ int expand_downwards(struct vm_area_struct *vma, if (error) return error; - /* Enforce stack_guard_gap */ - gap_addr = address - stack_guard_gap; - if (gap_addr > address) - return -ENOMEM; - prev = vma->vm_prev; - if (prev && prev->vm_end > gap_addr) { - if (!(prev->vm_flags & VM_GROWSDOWN)) - return -ENOMEM; - /* Check that both stack segments have the same anon_vma? */ - } - /* We must make sure the anon_vma is allocated. */ if (unlikely(anon_vma_prepare(vma))) return -ENOMEM; @@ -2381,25 +2341,28 @@ int expand_downwards(struct vm_area_struct *vma, return error; } -/* enforced gap between the expanding stack and other mappings. */ -unsigned long stack_guard_gap = 256UL<